﻿using System.Collections.Generic;
using System.Xml.Linq;
using System;
using DVK.SP2007;

namespace DVK.SP2007.UniversalClient
{
    /// <summary>
    /// Encapsulates the Transport element from Dvk message data xml. 
    /// 
    /// <remarks>
    /// Sample XML it helps to manage:
    /// 
    /// &lt;dhl:transport xmlns:dhl="http://www.riik.ee/schemas/dhl"&gt;
    /// &lt;!-- üks saatja info blokk --&gt; 
    ///  &lt;dhl:saatja&gt;
    ///    &lt;dhl:regnr&gt;Saatja asutuse registreerimisnumber&lt;/dhl:regnr&gt;
    ///    &lt;dhl:isikukood&gt;Saatja isikukood&lt;/dhl:isikukood&gt;
    ///    &lt;dhl:ametikoha_kood&gt;Saatja ametikoha kood&lt;/dhl:ametikoha_kood&gt;
    ///    &lt;dhl:epost&gt;Saatja eposti aadress&lt;/dhl:epost&gt;
    ///    &lt;dhl:nimi&gt;Saatja nimi&lt;/dhl:nimi&gt;
    ///    &lt;dhl:osakonna_kood&gt;Saatja struktuuriüksuse asutusesisene kood&lt;/dhl:osakonna_kood&gt;
    ///    &lt;dhl:osakonna_nimi&gt; Saatja struktuuriüksuse nimi&lt;/dhl:osakonna_nimi&gt;
    ///  &lt;/dhl:saatja&gt;
    /// 	 
    ///  &lt;!-- piiramatu arv saaja info blokke --&gt;
    ///  &lt;dhl:saaja&gt;
    ///    &lt;dhl:regnr&gt;Saaja asutuse registreerimisnumber&lt;/dhl:regnr&gt;
    ///    &lt;dhl:isikukood&gt;Saatja isikukood&lt;/dhl:isikukood&gt;
    ///    &lt;dhl:ametikoha_kood&gt;Saaja ametikoha kood&lt;/dhl:ametikoha_kood&gt;
    ///    &lt;dhl:epost&gt;Saaja eposti aadress&lt;/dhl:epost&gt;
    ///    &lt;dhl:nimi&gt;Saaja nimi&lt;/dhl:nimi&gt;
    ///    &lt;dhl:osakonna_kood&gt;Saaja struktuuriüksuse asutusesisene kood&lt;/dhl:osakonna_kood&gt;
    ///    &lt;dhl:osakonna_nimi&gt; Saaja struktuuriüksuse nimi&lt;/dhl:osakonna_nimi&gt;
    ///  &lt;/dhl:saaja&gt;
    ///  &lt;dhl:saaja&gt;
    ///    &lt;!--....--&gt;
    ///  &lt;/dhl:saaja&gt;
    /// &lt;/dhl:transport&gt;
    /// </remarks>
    /// </summary>
    public class DvkTransportXmlPart
    {
        #region ElementNames
        public static readonly XName ElementNameReceiver = XName.Get("saaja", DvkXml.RootNamespace);
        public static readonly XName ElementNameSender = XName.Get("saatja", DvkXml.RootNamespace);
        public static readonly XName ElementNameOrganizationCode = XName.Get("regnr", DvkXml.RootNamespace);
        public static readonly XName ElementNamePersonCode = XName.Get("isikukood", DvkXml.RootNamespace);
        public static readonly XName ElementNameJobCode = XName.Get("ametikoha_kood", DvkXml.RootNamespace);
        public static readonly XName ElementNameEmail = XName.Get("epost", DvkXml.RootNamespace);
        public static readonly XName ElementNamePersonName = XName.Get("nimi", DvkXml.RootNamespace);
        public static readonly XName ElementNameOrganizationUnitCode = XName.Get("osakonna_kood", DvkXml.RootNamespace);
        public static readonly XName ElementNameOrganizationUnitName = XName.Get("osakonna_nimi", DvkXml.RootNamespace);
        public static readonly XName ElementNameTransport = XName.Get("transport", DvkXml.RootNamespace);
        #endregion

        private XElement _transportXmlElement;

        /// <summary>
        /// Gets the xml as XElement.
        /// </summary>
        /// <value>The element.</value>
        public XElement Element
        {
            get
            {
                return _transportXmlElement;
            }
        }

        /// <summary>
        /// Create new empty DvkTransportMessagePart
        /// </summary>
        public DvkTransportXmlPart() : this(new XElement(ElementNameTransport)) { }

        /// <summary>
        /// Load DvkTransportMeesagePart xml from string.
        /// </summary>
        /// <param name="xml"></param>
        public DvkTransportXmlPart(string xml) : this(XElement.Parse(xml)) { }

        /// <summary>
        /// Initialize the class using XElement, which contains the transport xml element and its contents.
        /// </summary>
        /// <param name="xml"></param>
        public DvkTransportXmlPart(XElement xml)
        {
            _transportXmlElement = xml;
        }

        /// <summary>
        /// Adds message recipient to Transport xml.
        /// </summary>
        /// <param name="recipient">The recipient.</param>
        /// <returns></returns>
        public XElement AddRecipient(SenderReceiverInfo recipient)
        {
            return AddSenderOrRecipient(ElementNameReceiver, recipient);
        }

        /// <summary>
        /// Adds message sender to transport xml.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <returns></returns>
        public XElement AddSender(SenderReceiverInfo sender)
        {
            if (_transportXmlElement.Element(ElementNameSender) != null)
            {
                throw new DvkException("Only one sender can be added.");
            }

            return AddSenderOrRecipient(ElementNameSender, sender);
        }

        /// <summary>
        /// Gets the sender information from transport xml.
        /// </summary>
        /// <returns></returns>
        public SenderReceiverInfo GetSender()
        {
            var sender = GetSenderElement();
            return CreateSenderReceiverInfo(sender);
        }

        /// <summary>
        /// Gets the sender element.
        /// </summary>
        /// <returns></returns>
        public XElement GetSenderElement()
        {
            return _transportXmlElement.Element(ElementNameSender);
        }

        /// <summary>
        /// Gets the recipient elements.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<XElement> GetRecipientElements()
        {
            return _transportXmlElement.Elements(ElementNameReceiver);
        }

        /// <summary>
        /// Gets the recipients as recipient information instances.
        /// </summary>
        /// <returns></returns>
        public IList<SenderReceiverInfo> GetRecipients()
        {
            var result = new List<SenderReceiverInfo>();
            foreach (var recipientElement in GetRecipientElements())
            {
                result.Add(CreateSenderReceiverInfo(recipientElement));
            }
            return result;
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// 
        /// Turns the Element to Xml string.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return _transportXmlElement.ToString();
        }

        /// <summary>
        /// Creates the sender receiver info.
        /// Helper method.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        private SenderReceiverInfo CreateSenderReceiverInfo(XElement element)
        {
            return new SenderReceiverInfo()
            {
                Person = new UnitInfo()
                {
                    Code = XmlHelper.SafeGetElement(element, ElementNamePersonCode),
                    Name = XmlHelper.SafeGetElement(element, ElementNamePersonName)
                },
                Email = XmlHelper.SafeGetElement(element, ElementNameEmail),
                JobCode = XmlHelper.SafeGetElement(element, ElementNameJobCode),
                Organisation = new UnitInfo()
                {
                    Code = XmlHelper.SafeGetElement(element, ElementNameOrganizationCode)
                },
                OrganisationUnit = new UnitInfo()
                {
                    Code = XmlHelper.SafeGetElement(element, ElementNameOrganizationUnitCode),
                    Name = XmlHelper.SafeGetElement(element, ElementNameOrganizationUnitName)
                }
            };
        }


        /// <summary>
        /// Adds the sender or recipient.
        /// Helper method.
        /// </summary>
        /// <param name="senderOrRecipientName">Name of the sender or recipient.</param>
        /// <param name="senderOrRecipientInfo">The sender or recipient info.</param>
        /// <returns></returns>
        private XElement AddSenderOrRecipient(XName senderOrRecipientName, SenderReceiverInfo senderOrRecipientInfo)
        {
            var result = new XElement(
                senderOrRecipientName,
                XmlHelper.CreateElement(ElementNameOrganizationCode, senderOrRecipientInfo.Organisation.Code),
                XmlHelper.CreateElement(
                                ElementNameOrganizationUnitCode,
                                (senderOrRecipientInfo.OrganisationUnit == null ? null : senderOrRecipientInfo.OrganisationUnit.Code)
                            ),
                XmlHelper.CreateElement(
                                ElementNameOrganizationUnitName,
                                (senderOrRecipientInfo.OrganisationUnit == null ? null : senderOrRecipientInfo.OrganisationUnit.Name)
                            ),
                XmlHelper.CreateElement(
                                ElementNamePersonCode,
                                (senderOrRecipientInfo.Person == null ? null : senderOrRecipientInfo.Person.Code)
                            ),
                //If the person doesnt exist, use organisation name.
                XmlHelper.CreateElement(
                                ElementNamePersonName,
                                (senderOrRecipientInfo.Person == null ? senderOrRecipientInfo.Organisation.Name : senderOrRecipientInfo.Person.Name)
                                ),
                XmlHelper.CreateElement(ElementNameEmail, senderOrRecipientInfo.Email),
                XmlHelper.CreateElement(ElementNameJobCode, senderOrRecipientInfo.JobCode)
            );
            _transportXmlElement.Add(result);
            return result;
        }
    }
}